package com.jt.www.aop;

import com.jt.www.exception.IdempotentException;
import com.jt.www.model.reps.GenericDataResponse;
import com.jt.www.util.JsonUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author xq.wu03
 * @Classname AvoidRepeatableCommitAspect
 * @Description 重复提交aop
 * @create 2020-03-24 16:16
 */
@Aspect
@Component
public class AvoidRepeatableCommitAspect {

    public static final Logger log = LoggerFactory.getLogger(AvoidRepeatableCommitAspect.class);
    public final String idgPrefix = "IDG-SVC:RESUB-TOKEN:";
    public final String eduPrefix = "EDU-SVC:RESUB-TOKEN:";
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * @param proceedingJoinPoint
     */
    @Around("@annotation(com.jt.www.annotations.AvoidRepeatableCommit)")
    public ResponseEntity around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        // 获取请求
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        // 获取请求头里面的幂等token
        String resubmitToken = request.getHeader("X-RESUB-TOKEN");
        if (StringUtils.isEmpty(resubmitToken)) {
            throw new IdempotentException(HttpStatus.BAD_REQUEST.toString(), "token check fail");
        }
        String key = eduPrefix + resubmitToken;
        Boolean idempotentFlag = stringRedisTemplate.opsForValue().setIfAbsent(key, "0");
        ResponseEntity responseEntity = GenericDataResponse.errorWithMsg("添加失败");
        if (idempotentFlag) {
            try {
                // 插入唯一token成功，进行处理
                String idgKey = idgPrefix + resubmitToken;
                Boolean hasKey = stringRedisTemplate.hasKey(idgKey);
                if (hasKey) {
                    // idg存在token，继续业务处理
                    Object proceed = proceedingJoinPoint.proceed();
                    String code = JsonUtil.object2Json(((ResponseEntity) proceed).getStatusCodeValue());
                    if (String.valueOf(HttpStatus.OK.value()).equals(code)) {
                        // 方法执行成功，删除idg的token
                        stringRedisTemplate.delete(idgKey);
                        // 方法执行成功，删除唯一token
                        stringRedisTemplate.delete(key);
                        responseEntity = ((ResponseEntity) proceed);
                        return responseEntity;
                    }
                } else {
                    // idg不存在token
                    throw new IdempotentException(HttpStatus.BAD_REQUEST.toString(), "token check fail");
                }
            } catch (Exception e) {
                // 删除唯一token，抛出异常
                stringRedisTemplate.delete(key);
                throw e;
            }
        } else {
            // 插入唯一token失败，进行处理
            throw new IdempotentException(HttpStatus.BAD_REQUEST.toString(), "token check fail");
        }
        return responseEntity;
    }

}

